/****************************************************************************
 * Copyright 2009 Huascar A. Sanchez                                        *
 *                                                                          *
 * Licensed under the Apache License, Version 2.0 (the "License");          *
 * you may not use this file except in compliance with the License.         *
 * You may obtain a copy of the License at                                  *
 *                                                                          *
 *     http://www.apache.org/licenses/LICENSE-2.0                           *
 *                                                                          *
 * Unless required by applicable law or agreed to in writing, software      *
 * distributed under the License is distributed on an "AS IS" BASIS,        *
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. *
 * See the License for the specific language governing permissions and      *
 * limitations under the License.                                           *
 ****************************************************************************/
package com.gotobject.filter.command;

import static com.gotobject.filter.common.Iterables.capturedWildCard;
import com.gotobject.filter.internal.Objects;
import com.gotobject.filter.spi.Function;

import java.util.ArrayList;
import java.util.Collections;

/**
 * @author huascar.sanchez@gmail.com (Huascar A. Sanchez)
 */
@SuppressWarnings({"RedundantTypeArguments"})
public abstract class Command <T> implements Function<Iterable<? extends T>, Iterable<T>> {

    /**
     * execute the command with an input x.
     * @param x
     *      input iterable.
     * @return
     *      return the
     */
    public Iterable<T> execute(Object x){
        return this.tryApply(Objects.<T>asIterable(x));
    }

    /**
     * no parameter execution of the command.
     * @return
     *      an empty and unmodifiable list.
     */
    public Iterable<T> execute(){
        return execute(none());
    }

    /**
     * null object, the method way.
     * @param <T>
     *      bound type.
     * @return
     *      an empty and unmodifiable list.
     */
    public static <T> Iterable<T> none(){
        return Collections.unmodifiableList(new ArrayList<T>(0));
    }



    /**
     * Generic Call. No guarantees of correctness will be made to the returning result
     * if the programmer decides to change the state of the args that were passed.
     * Command's main purpose is to expand the visibility of those args.
     * e.g., writing them to a file.
     *
     * @param iterable
     *      function's input.
     * @return
     *      the result of the play.
     * @throws Exception
     *      if the object's play failed.
     */
    public abstract Iterable<T> apply(Iterable<? extends T> iterable) throws
    Exception;

    /**
     * return the input back to the caller.
     * @param in
     *      input.
     * @param <T>
     *      bound type.
     * @return
     *      input.
     */
    public static <T> Iterable<T> self(Iterable<? extends T> in){
        return capturedWildCard(in);
    }



    /**
     * try to call the closure and throw a runtime exception if unable to
     * invoke the call.
     *
     * @param me
     *      arguments
     * @return <T>
     *      return object.
     * @throws RuntimeException
     *      if the program was unable to invoke the call.
     */
    private Iterable<T> tryApply(Iterable<? extends T> me) {
        try {
            return Objects.<Iterable<T>>as(this.apply(me));
        } catch (Exception e) {
            throw new IllegalStateException(e);
        }
    }
}
